/*
 * Filename PreOrderServiceImpl.java 2022年10月10日
 * Copyright © Ehome Co.Ltd. All Rgiths Reserved.
 * @author wuyingchao
 */
package com.ehome.poct.core.service.order;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ehome.paymentcenter.api.pay.BasePayReqCO;
import com.ehome.paymentcenter.api.pay.BaseQueryReqCO;
import com.ehome.paymentcenter.api.pay.BaseRspCO;
import com.ehome.paymentcenter.api.pay.constant.PayStatus;
import com.ehome.paymentcenter.api.pay.domain.PayExtend;
import com.ehome.paymentcenter.api.pay.prepay.CashierPayQueryRspCO;
import com.ehome.paymentcenter.api.pay.qrcode.QrCodeRspCO;
import com.ehome.poct.base.api.enums.BusinessOrderTypeEnums;
import com.ehome.poct.base.api.enums.CheckStatusEnums;
import com.ehome.poct.base.api.enums.StripTypeEnums;
import com.ehome.poct.core.api.constant.enums.ScanTypeEnums;
import com.ehome.poct.core.api.constant.enums.SysConstant;
import com.ehome.poct.core.api.dto.check.CheckProjectDTO;
import com.ehome.poct.core.api.dto.check.TestRecordDetailDTO;
import com.ehome.poct.core.api.dto.check.TestReportDataConfigDTO;
import com.ehome.poct.core.api.dto.order.*;
import com.ehome.poct.core.api.dto.patient.TermPatientDTO;
import com.ehome.poct.core.api.virtual.*;
import com.ehome.poct.core.api.vo.order.*;
import com.ehome.poct.core.constant.BizCode;
import com.ehome.poct.core.constant.OrderBizCodeEnums;
import com.ehome.poct.core.constant.PayBizCodeEnums;
import com.ehome.poct.core.mapping.TestOrderMapping;
import com.ehome.poct.core.properties.PayProperties;
import com.ehome.poct.core.repository.CheckProjectRepository;
import com.ehome.poct.core.repository.TestReportDataConfigRepository;
import com.ehome.poct.core.repository.check.TestRecordDetailRepository;
import com.ehome.poct.core.repository.order.*;
import com.ehome.poct.core.repository.report.TermPatientRepository;
import com.ehome.poct.core.service.mapping.PreOrderMapping;
import com.ehome.poct.core.service.pay.AbstractPayStrategy;
import com.ehome.poct.core.service.pay.PayFactory;
import com.ehome.poct.core.service.rpc.CorePayClient;
import com.ehome.poct.core.utils.EHomeAssert;
import com.ehome.web.entity.ResponseWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 支付前置订单服务
 *
 * @author wyc
 * @since 2022/10/10 16:15
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class PreOrderServiceImpl implements PreOrderService {
    public static final String ORDER_KEY_PREFIX = "client_test_order:";
    public static final String PAY_KEY_PREFIX = "client_test_pay_info:";
    private final TestReportDataConfigRepository reportConfigRepository;
    private final TestStripPriceProfitRepository profitRepository;
    private final TestOrderRepository orderRepository;
    private final TestOrderItemRepository itemRepository;
    private final PreOrderMapping preOrderMapping;
    private final TermPatientRepository patientRepository;
    private final TestRecordDetailRepository recordDetailRepository;
    private final CheckProjectRepository checkProjectRepository;
    private final TestOrderMapping orderMapping;
    private final TestOrderService orderService;
    private final CorePayClient payClient;
    private final RedisTemplate redisTemplate;
    private final PayProperties payProperties;
    private final PromotionBundlePriceProfitConfRepository promotionBundlePriceProfitConfRepository;

    private final PayFactory payFactory;

    private final TestOrderCheckRecordService testOrderCheckRecordService;

    private final TestOrderExtendsRepository orderExtendsRepository;

    private final TestOrderInternalPayService orderInternalPayService;

    private final TestRecordDetailService recordDetailService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public PreOrderRspVO order(PrePlaceOrderDTO placeOrder) {
        final var orderNo = placeOrder.getOrderNo();
        final var strips = placeOrder.getStripCode();
        final var patientDTO = patientRepository.getById(placeOrder.getPatientId());
        final var reportConfigs = reportConfigRepository.list();
        final var bldProjectMap = checkProjectRepository.list().stream()
                .collect(Collectors.toMap(CheckProjectDTO::getCheckProjectCode, Function.identity()));

        List<TestStripPriceProfitDTO> priceProfitDTOList = profitRepository
                .list(new TestStripPriceProfitDTO().setTestStripPriceProfitSchemeId(placeOrder.getProfitId()));
        final var profitMap = priceProfitDTOList.stream()
                .collect(Collectors.toMap(TestStripPriceProfitDTO::getStripTypeCode, Function.identity()));

        //查询捆绑促销活动 价格体系，分润体系配置表  productCombineCode 0617   reportCode 组合包中含有的报告编码
        //sale_price  售价    realSalePrice 真是售价
        List<PromotionBundlePriceProfitConfDTO> bindingPriceList = promotionBundlePriceProfitConfRepository.getValidBundlerPriceInfos(placeOrder.getProfitId());
        Map<String, Integer> combineCodeMap = bindingPriceList.stream().collect(Collectors.toMap(profitDTO -> profitDTO.getProductCombineCode() + "_" + profitDTO.getReportCode(), PromotionBundlePriceProfitConfDTO::getStripTypeCode, (o1, o2) -> o1));
        //获取配置表中的联测配置数据
        List<TestReportDataConfigDTO> uniList = reportConfigs.stream()
                .filter(it -> strips.contains(it.getStripTypeCode()) && it.getReportType().equals(2) && !it.getTestPropertyType().equals(4))
                .collect(Collectors.toList());
        //按照检测编码进行分组
        final var configMap = uniList.stream().collect(Collectors.groupingBy(TestReportDataConfigDTO::getReportCode));
        //先拿到所有联测包含订单项
        List<TestOrderItemDTO> uniItems = configMap.values().stream().
                filter(it -> it.size() >= 2)
                .map(it -> preOrderMapping.to(it.get(0), null, BigDecimal.ZERO, orderNo))
                .collect(Collectors.toList());

        //诊所存在捆绑活动且检测项目大于等于2
        //1.得到诊所存在绑定活动的捆绑项目  0617  0917 捆绑的检测配置项在检测的时候只会单独存在 不可能出先交集
        //比如 1003价格方案  配置了活动捆绑项：0617,0917 那么在检测的时候只会出现 0617或者0917 这2个检测项目，如果检测中出现06,09,17这3个项目同时存在那么它只可能是测试数据。
        //那么它的计算方案为：0617 + 0917
        //得到捆绑组合的项（不包含总价）比如 06 17 = 50  这里包好了06  17  不包含50
        Map<String, List<PromotionBundlePriceProfitConfDTO>> existenceBundleCodeList = bindingPriceList.stream()
                .filter(b -> uniList.stream().anyMatch(u -> CharSequenceUtil.isNotBlank(u.getPromotionProductCode()) && u.getPromotionProductCode().equals(b.getProductCombineCode())))
                .filter(b -> reportConfigs.stream().anyMatch(s -> s.getStripTypeCode().equals(b.getStripTypeCode())))
                .collect(Collectors.groupingBy(PromotionBundlePriceProfitConfDTO::getProductCombineCode));
        //取它们的差集得到捆绑的价格 这里只要50
        Map<String, BigDecimal> bundlerCodePrice = bindingPriceList.stream()
                .filter(b -> uniList.stream().anyMatch(u -> CharSequenceUtil.isNotBlank(u.getPromotionProductCode()) && u.getPromotionProductCode().equals(b.getProductCombineCode())))
                .filter(b -> reportConfigs.stream().noneMatch(s -> s.getStripTypeCode().equals(b.getStripTypeCode())))
                .collect(Collectors.toMap(PromotionBundlePriceProfitConfDTO::getProductCombineCode, PromotionBundlePriceProfitConfDTO::getRealSalePrice));
        //活动捆绑code和报告code映射关系
        Map<String, String> bundlerCodeMap = bindingPriceList.stream()
                .filter(b -> uniList.stream().anyMatch(u -> CharSequenceUtil.isNotBlank(u.getPromotionProductCode()) && u.getPromotionProductCode().equals(b.getProductCombineCode())))
                .filter(b -> reportConfigs.stream().noneMatch(s -> s.getStripTypeCode().equals(b.getStripTypeCode())))
                .collect(Collectors.toMap(PromotionBundlePriceProfitConfDTO::getProductCombineCode, PromotionBundlePriceProfitConfDTO::getReportCode));
        //用来存储已经使用了优惠活动价格的项目
        List<Integer> discountStripsCodes = new ArrayList<>();

        //得到活动优惠的金额
        //判断本次检测是否存在联测配置 0617  0917
        if (existenceBundleCodeList.entrySet().size() > 0) {
            for (Map.Entry<String, List<PromotionBundlePriceProfitConfDTO>> entry : existenceBundleCodeList.entrySet()) {
                //如果本次的检测包含了捆绑活动里面的所有配置项目，那么就是用活动金额
                List<Integer> integerList = entry.getValue().stream().map(PromotionBundlePriceProfitConfDTO::getStripTypeCode).collect(Collectors.toList());
                //说明存在联测报告，生成联测订单
                if (new HashSet<>(strips).containsAll(integerList)) {
                    BigDecimal bigDecimal = bundlerCodePrice.getOrDefault(entry.getKey(), BigDecimal.ZERO);
                    discountStripsCodes.addAll(integerList);
                    uniItems.forEach(itemDTO -> {
                        //如果默认联测里面的报告code 和捆绑活动里面的报告code一直，那么修改的它的金额为活动金额
                        if (itemDTO.getTestReportTypeCode().equals(bundlerCodeMap.get(entry.getKey()))) {
                            itemDTO.setFee(bigDecimal);
                            itemDTO.setStripTypeCode(combineCodeMap.get(itemDTO.getPromotionProductCode() + "_" + itemDTO.getTestReportTypeCode()));
                        }
                    });
                }
            }
        }

        List<Integer> noBundleCodeList = strips.stream().filter(d -> discountStripsCodes.stream().noneMatch(s -> s.equals(d))).collect(Collectors.toList());
        checkStripPriceProfit(priceProfitDTOList, noBundleCodeList);

        List<TestReportDataConfigDTO> sigReportConfigs = reportConfigs.stream()
                .filter(it -> strips.contains(it.getStripTypeCode()) && strips.contains(it.getRealStripTypeCode()) && it.getReportType().equals(1))
                .collect(Collectors.toList());

        List<TestOrderItemDTO> orderItems = sigReportConfigs.stream()
                .map(it -> preOrderMapping.to(it, it.getStripTypeCode(),
                        noBundleCodeList.contains(it.getStripTypeCode()) ? profitMap.get(it.getStripTypeCode()).getSalePrice() : BigDecimal.ZERO
                        , orderNo)
                )
                .collect(Collectors.toList());

        orderItems.addAll(uniItems);
        //血常规没有特性处理
        final var bldItems = strips.stream().filter(bldProjectMap::containsKey)
                .map(it -> new TestOrderItemDTO().setTestOrderNo(orderNo)
                        .setOrderItemName(bldProjectMap.get(it).getCheckProjectName())
                        .setTestPoctReportType(bldProjectMap.get(it).getCheckProjectCode() == 121 ? 3 : 1)
                        .setFee(profitMap.get(it).getSalePrice())
                        .setStripTypeCode(it))
                .collect(Collectors.toList());
        orderItems.addAll(bldItems);
        final var totalMoney = orderItems.stream().map(TestOrderItemDTO::getFee)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        final var order = preOrderMapping.to(placeOrder, totalMoney, 2, orderItems);
        order.setCheckStatus(CheckStatusEnums.TO_BE_TESTED);
        order.setBusinessOrderType(BusinessOrderTypeEnums.PRE_TRADE);
        final var itemPrices = orderService.getPriceItemByOrderItem(orderItems);
        orderItems.stream()
                .filter(orderItem -> "U_CRP_SAA_REPORT".equals(orderItem.getTestReportTypeCode()))
                .forEach(orderItem -> orderItem.setStripTypeCode(StripTypeEnums.SAA_CRP.getStripTypeCode()));
        itemRepository.batchInsert(orderItems);
        orderRepository.save(order);

        final List<TestRecordDetailDTO> recordDtls = orderInternalPayService.convertRecordDetailList(placeOrder, orderItems);
        recordDetailRepository.batchInsert(recordDtls);

        // 保存订单拓展信息 缺少经纬度等，在创建报告的时候给补上
        saveOrderExtInfo(orderNo, order);

        QrCodeVO qrCodeVO = new QrCodeVO();
        qrCodeVO.setMoney(order.getPayMoney());
        qrCodeVO.setPromptMsg(PayStatus.INIT.getDesc());
        qrCodeVO.setOrderStatus(PayStatus.INIT.getStatus());
        return new PreOrderRspVO().setQrCode(qrCodeVO).setPriceItems(itemPrices)
                .setPatient(preOrderMapping.to(patientDTO))
                .setCreateTime(LocalDateTime.now())
                .setOrderNo(orderNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PreOrderRspVO orderV2(PrePlaceOrderDTO placeOrder) {
        final var orderNo = placeOrder.getOrderNo();
        final var strips = placeOrder.getStripCode();
        final var patientDTO = patientRepository.getById(placeOrder.getPatientId());

        List<TestOrderItemDTO> orderItemDTOList = orderInternalPayService.convertOrderItems(placeOrder.getClinicId(), strips, orderNo);

        BigDecimal totalMoney = orderItemDTOList.stream().map(TestOrderItemDTO::getFee)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        final var order = preOrderMapping.to(placeOrder, totalMoney, 2, orderItemDTOList);
        order.setCheckStatus(CheckStatusEnums.TO_BE_TESTED);
        order.setBusinessOrderType(BusinessOrderTypeEnums.PRE_TRADE);

        final var itemPrices = orderService.getPriceItemByOrderItem(orderItemDTOList);
        orderItemDTOList.stream()
                .filter(orderItem -> StripTypeEnums.SAA_CRP_SINGLE_PAPER.getReportTypeCode().equals(orderItem.getTestReportTypeCode()))
                .forEach(orderItem -> orderItem.setStripTypeCode(StripTypeEnums.SAA_CRP.getStripTypeCode()));
        itemRepository.batchInsert(orderItemDTOList);
        orderRepository.save(order);

        List<TestRecordDetailDTO> recordDtls = orderInternalPayService.convertRecordDetailList(placeOrder, orderItemDTOList);
        recordDetailService.saveRecord(recordDtls);

        // 保存订单拓展信息 缺少经纬度等，在创建报告的时候给补上
        saveOrderExtInfo(orderNo, order);

        QrCodeVO qrCodeVO = new QrCodeVO();
        qrCodeVO.setMoney(order.getPayMoney());
        qrCodeVO.setPromptMsg(PayStatus.INIT.getDesc());
        qrCodeVO.setOrderStatus(PayStatus.INIT.getStatus());
        return new PreOrderRspVO().setQrCode(qrCodeVO).setPriceItems(itemPrices)
                .setPatient(preOrderMapping.to(patientDTO))
                .setCreateTime(LocalDateTime.now())
                .setOrderNo(orderNo);
    }


    /**
     * 获取检测项目的真实费用
     *
     * @param stripTypeCode        当前订单项中的检测code
     * @param promotionProductCode 当前订单项中活动捆绑code
     * @param bindingPriceList     诊所-活动捆绑表里面的所有数据
     * @return
     */
    private BigDecimal activityBundlePrice(Integer stripTypeCode, String promotionProductCode, List<PromotionBundlePriceProfitConfDTO> bindingPriceList, BigDecimal fee) {
        if (ObjectUtil.isNotEmpty(bindingPriceList)) {
            PromotionBundlePriceProfitConfDTO dto = bindingPriceList.stream().filter(f -> f.getProductCombineCode().equals(promotionProductCode) && f.getStripTypeCode().equals(stripTypeCode)).findFirst().orElse(null);
            if (null != dto) {
                return dto.getRealSalePrice();
            }
            return fee;
        }
        return fee;
    }


    @Override
    public PreOrderRspVO reOrder(String orderNo) {
        final var order = orderRepository.getByColumn("testOrderNo", orderNo);
        final var orderItems = itemRepository.list(new TestOrderItemDTO().setTestOrderNo(orderNo));
        TermPatientDTO patientDTO = new TermPatientDTO().setName(SysConstant.DEFAULT_NAME);
        if (Objects.nonNull(order.getPatientId())) {
            patientDTO = patientRepository.getById(order.getPatientId());
        }

        String reservationCode = null;
        TestOrderCheckRecordDTO testOrderCheckRecordDTO = testOrderCheckRecordService.selectOne(new TestOrderCheckRecordDTO().setOrderNo(orderNo));
        if (Objects.nonNull(testOrderCheckRecordDTO) && Objects.nonNull(testOrderCheckRecordDTO.getReservationCode())) {
            reservationCode = String.format("%04d", testOrderCheckRecordDTO.getReservationCode());
        }

        final var itemPrices = orderService.getPriceItemByOrderItem(orderItems);
        QrCodeVO qrCodeVO = new QrCodeVO();
        qrCodeVO.setMoney(order.getPayMoney());
        if (PayStatus.INIT.getStatus().equals(order.getStatus())) {
            qrCodeVO.setPromptMsg(PayStatus.INIT.getDesc());
        }
        qrCodeVO.setOrderStatus(order.getStatus());
        return new PreOrderRspVO().setQrCode(qrCodeVO)
                .setPriceItems(itemPrices).setPatient(preOrderMapping.to(patientDTO))
                .setCreateTime(order.getCreateTime()).setOrderNo(orderNo)
                .setPay(order.getIsPay()).setReservationCode(reservationCode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PreOrderPayRspVO pay(PreOrderPayReqDTO payReqDTO) {
        final var order = orderRepository.getByColumn("testOrderNo", payReqDTO.getOrderNo());
        EHomeAssert.notNull(order, OrderBizCodeEnums.NOT_FOUND_TEST_ORDER, payReqDTO.getOrderNo());
        EHomeAssert.isTrue(!order.getIsPay(), OrderBizCodeEnums.DUPLICATE_PAYMENT, payReqDTO.getOrderNo());
        final var orderItems = itemRepository.list(new TestOrderItemDTO().setTestOrderNo(payReqDTO.getOrderNo()));
        final var itemPrices = orderService.getPriceItemByOrderItem(orderItems);
        final var amounts = orderMapping.to(itemPrices);

        BasePayReqCO basePayReqCO = orderMapping.to(order, payProperties.getTimeout() + "m", payProperties.getPreNotifyUrl(), new PayExtend(amounts), "血常规订单");
        if (ScanTypeEnums.B2C.equals(payReqDTO.getScanType())) {
            EHomeAssert.isTrue(StrUtil.isNotBlank(payReqDTO.getAuthCode()), PayBizCodeEnums.AUTH_CODE_NOT_NULL);
            basePayReqCO = orderMapping.to(order, payReqDTO.getAuthCode(), payProperties.getTimeout() + "m", payProperties.getPreNotifyUrl(), new PayExtend(amounts), "血常规订单");
        }

        // 不同类型订单 回调地址不一样
        basePayReqCO.setNotifyUrl(payProperties.getNotifyUrl());
        if (BusinessOrderTypeEnums.PRE_TRADE.equals(order.getBusinessOrderType())) {
            basePayReqCO.setNotifyUrl(payProperties.getPreNotifyUrl());
        }

        AbstractPayStrategy<BasePayReqCO, BaseRspCO> payStrategy = payFactory.getPayStrategy(basePayReqCO);
        PayChannelRespVO<BaseRspCO> payChannelRespVO = payStrategy.pay(basePayReqCO);

        // 请求支付渠道失败
        EHomeAssert.isTrue(payChannelRespVO.isSuccess(), PayBizCodeEnums.PAY_CHANNEL_FAIL, payChannelRespVO.getMsg());

        // 公众号支付 需要缓存支付二维码
        if (ScanTypeEnums.C2B.equals(payChannelRespVO.getScanType())) {
            QrCodeVO qrCodeVO = orderMapping.to((QrCodeRspCO) payChannelRespVO.getData(), order.getTotalMoney(), payProperties.getTimeout() * 60);
            cacheOrder(qrCodeVO, orderMapping.toStatus(order));
        }
        // 保存渠道订单编号 http://jira.ehome.com/browse/HARDSOFT-1565
        order.setOutOrderNo(payChannelRespVO.getData().getOutOrderNo());
        orderService.update(order.getTestOrderId(), order);
        return PreOrderPayRspVO.builder().payInfo(BeanUtil.copyProperties(payChannelRespVO.getData(), UnificationPayVO.PayInfoDTO.class)).scanType(payChannelRespVO.getScanType()).build();
    }

    @Override
    public PreOrderPayRspVO payV2(PreOrderPayReqDTO payReqDTO) {
        final var order = orderRepository.getByColumn("testOrderNo", payReqDTO.getOrderNo());
        EHomeAssert.notNull(order, OrderBizCodeEnums.NOT_FOUND_TEST_ORDER, payReqDTO.getOrderNo());
        EHomeAssert.isTrue(!order.getIsPay(), OrderBizCodeEnums.DUPLICATE_PAYMENT, payReqDTO.getOrderNo());
        UnificationPayVO unificationPayVO = orderInternalPayService.internalPay(order, payReqDTO.getScanType(), payReqDTO.getAuthCode());
        // 公众号支付 需要缓存支付二维码
        if (ScanTypeEnums.C2B.equals(payReqDTO.getScanType())) {
            QrCodeVO qrCodeVO = orderMapping.to(BeanUtil.copyProperties(unificationPayVO.getPayInfo(), QrCodeRspCO.class), order.getTotalMoney(), payProperties.getTimeout() * 60);
            cacheOrder(qrCodeVO, orderMapping.toStatus(order));
        }
        // 保存渠道订单编号 http://jira.ehome.com/browse/HARDSOFT-1565
        orderService.update(order.getTestOrderId(), order);
        return PreOrderPayRspVO.builder().payInfo(unificationPayVO.getPayInfo()).scanType(payReqDTO.getScanType()).build();
    }

    @Override
    public OrderStatusVO queryOrderStatus(String orderNo) {
        TestOrderDTO orderDTO = orderService.selectOne(new TestOrderDTO().setTestOrderNo(orderNo));
        EHomeAssert.notNull(orderDTO, OrderBizCodeEnums.NOT_FOUND_TEST_ORDER, orderNo);
        BaseQueryReqCO queryReqCO = new BaseQueryReqCO();
        queryReqCO.setOrderNo(orderNo);
        ResponseWrapper<CashierPayQueryRspCO> queryRspCOResponseWrapper = payClient.query(queryReqCO);
        Assert.isTrue(BizCode.SUCCESS.getBusiCode().equals(queryRspCOResponseWrapper.getBusiCode()), queryRspCOResponseWrapper.getMsg());
        CashierPayQueryRspCO data = queryRspCOResponseWrapper.getData();
        return orderMapping.toStatus(data);
    }

    @SuppressWarnings("unchecked")
    private void cacheOrder(QrCodeVO qrcode, OrderStatusVO status) {
        // 1. 缓存订单内容
        redisTemplate.opsForValue().set(PAY_KEY_PREFIX + qrcode.getOrderNo(), qrcode, payProperties.getTimeout(), TimeUnit.MINUTES);
        //// 2. 缓存订单状态
        //redisTemplate.opsForValue().set(ORDER_KEY_PREFIX + qrcode.getOrderNo(), status, payProperties.getTimeout(), TimeUnit.MINUTES);
    }

    /**
     * 检测项价格方案校验
     *
     * @param priceProfitDTOList
     * @param noBundleCodeList
     */
    private static void checkStripPriceProfit(List<TestStripPriceProfitDTO> priceProfitDTOList, List<Integer> noBundleCodeList) {
        List<Integer> configPriceStripeCodeList = priceProfitDTOList.stream().map(TestStripPriceProfitDTO::getStripTypeCode).collect(Collectors.toList());
        Collection<Integer> subtract = CollUtil.subtract(noBundleCodeList, configPriceStripeCodeList);
        if (CollUtil.isNotEmpty(subtract)) {
            log.error("价格方案错误，不存在的检查项 stripCodeList:[{}]", subtract);
        }
        EHomeAssert.isTrue(CollUtil.isEmpty(subtract), OrderBizCodeEnums.STRIP_DIVIDE_INTO_SCHEMES_ERROR);
    }

    /**
     * 保存订单拓展信息
     *
     * @param orderNo
     * @param order
     */
    private void saveOrderExtInfo(String orderNo, TestOrderDTO order) {
        TestOrderExtendsDTO extendsDTO = new TestOrderExtendsDTO();
        extendsDTO.setTestOrderExtendsId(IdUtil.getSnowflake().nextId());
        extendsDTO.setTestOrderNo(orderNo);
        extendsDTO.setName(order.getName());
        orderExtendsRepository.save(extendsDTO);
    }
}